"""
导航RAG管理路由
"""

import io
from datetime import datetime
from typing import List, Optional

import pandas as pd
from fastapi import APIRouter, HTTPException, UploadFile, File, Query
from fastapi.responses import StreamingResponse

from navigation.AIWebApiCallingService import AIWebApiCallingService
from pojo.ai_web_api_calling import (
    AIWebApiCallingCreate,
    AIWebApiCallingUpdate,
    AIWebApiCallingResponse,
    AIWebApiCallingQueryParams,
    AIWebApiCallingListResponse,
    AIWebApiCallingPathUpdate
)
from pojo.ai_web_api_calling_model import (
    AIWebApiCallingSearchRequest,
    AIWebApiCallingExport
)
from pydantic import BaseModel

router = APIRouter()


class BatchDeleteRequest(BaseModel):
    """批量删除请求模型"""
    page_ids: List[str]
    updated_by: str


@router.get("/list", summary="获取导航页面列表")
async def get_navigation_list(
        page_num: int = Query(1, ge=1, description="页码"),
        page_size: int = Query(20, ge=1, le=100, description="每页数量"),
        scene_id: Optional[str] = Query(None, description="场景ID筛选"),
        tenant_id: Optional[str] = Query(None, description="租户ID筛选"),
        page_name: Optional[str] = Query(None, description="页面名称模糊查询"),
        navigation_path: Optional[str] = Query(None, description="导航路径模糊查询"),
        created_by: Optional[str] = Query(None, description="创建者筛选"),
        is_deleted: int = Query(0, description="删除标记")
):
    """获取导航页面列表"""
    try:
        # 构建查询参数
        query_params = AIWebApiCallingQueryParams(
            scene_id=scene_id,
            tenant_id=tenant_id,
            page_name=page_name,
            navigation_path=navigation_path,
            created_by=created_by,
            is_deleted=is_deleted
        )

        # 调用服务层
        service_result = await AIWebApiCallingService.get_list(query_params, page_num, page_size)

        # 按照前端期望的格式包装返回结果
        return {
            "code": 200,
            "message": "获取导航页面列表成功",
            "data": {
                "items": service_result.items,
                "total": service_result.total,
                "page_num": page_num,
                "page_size": page_size
            }
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"获取导航页面列表失败: {str(e)}")


@router.post("/create", summary="创建导航页面")
async def create_navigation(data: AIWebApiCallingCreate):
    """创建导航页面"""
    try:
        # 调用服务层创建导航页面
        result = await AIWebApiCallingService.create(data)
        if result:
            return {
                "code": 200,
                "message": "创建导航页面成功",
                "data": result
            }
        else:
            return {
                "code": 500,
                "message": "创建导航页面失败",
                "data": None
            }
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"创建导航页面失败: {str(e)}")


@router.put("/{page_id}", summary="更新导航页面")
async def update_navigation(page_id: str, data: AIWebApiCallingUpdate):
    """更新导航页面"""
    try:
        # 调用服务层更新导航页面
        result = await AIWebApiCallingService.update(page_id, data)
        if result:
            return {
                "code": 200,
                "message": "更新导航页面成功",
                "data": result
            }
        else:
            return {
                "code": 404,
                "message": "导航页面不存在",
                "data": None
            }
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"更新导航页面失败: {str(e)}")


@router.delete("/{page_id}", summary="删除导航页面")
async def delete_navigation(page_id: str, updated_by: str = Query(..., description="操作者")):
    """删除导航页面（软删除）"""
    try:
        # 调用服务层删除导航页面
        success = await AIWebApiCallingService.delete(page_id, updated_by)
        if success:
            return {
                "code": 200,
                "message": "导航页面删除成功",
                "data": {"page_id": page_id}
            }
        else:
            return {
                "code": 404,
                "message": "导航页面不存在",
                "data": None
            }
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"删除导航页面失败: {str(e)}")


@router.post("/batch/delete", summary="批量删除导航页面")
async def batch_delete_navigation(request: BatchDeleteRequest):
    """批量删除导航页面（软删除）"""
    try:
        if not request.page_ids:
            return {
                "code": 400,
                "message": "请提供要删除的页面ID列表",
                "data": None
            }
        
        success_count = 0
        failed_ids = []
        
        # 逐个删除
        for page_id in request.page_ids:
            try:
                success = await AIWebApiCallingService.delete(page_id, request.updated_by)
                if success:
                    success_count += 1
                else:
                    failed_ids.append(page_id)
            except Exception as e:
                failed_ids.append(page_id)
                print(f"删除页面 {page_id} 失败: {str(e)}")
        
        return {
            "code": 200,
            "message": f"批量删除完成，成功删除 {success_count} 个页面",
            "data": {
                "success_count": success_count,
                "failed_count": len(failed_ids),
                "failed_ids": failed_ids
            }
        }
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"批量删除导航页面失败: {str(e)}")


@router.get("/{page_id}", summary="获取导航页面详情")
async def get_navigation_detail(page_id: str):
    """获取导航页面详情"""
    try:
        # 调用服务层获取导航页面详情
        result = await AIWebApiCallingService.get_by_id(page_id)
        if result:
            return {
                "code": 200,
                "message": "获取导航页面详情成功",
                "data": result
            }
        else:
            return {
                "code": 404,
                "message": "导航页面不存在",
                "data": None
            }
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"获取导航页面详情失败: {str(e)}")


@router.post("/export", summary="导出导航数据到Excel")
async def export_navigation_excel(request: AIWebApiCallingExport):
    """导出导航数据到Excel"""
    try:
        # 调用服务层获取导出数据
        data = await AIWebApiCallingService.export_data(request.scene_ids, request.include_deleted)

        # 创建DataFrame
        df = pd.DataFrame(data)

        # 创建Excel文件
        output = io.BytesIO()
        with pd.ExcelWriter(output, engine='openpyxl') as writer:
            df.to_excel(writer, sheet_name='导航数据', index=False)

        output.seek(0)

        # 返回文件流
        headers = {
            'Content-Disposition': f'attachment; filename="navigation_data_{datetime.now().strftime("%Y%m%d_%H%M%S")}.xlsx"'
        }

        return StreamingResponse(
            io.BytesIO(output.read()),
            media_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
            headers=headers
        )
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"导出Excel失败: {str(e)}")


@router.post("/import", summary="从Excel导入导航数据")
async def import_navigation_excel(
        file: UploadFile = File(..., description="Excel文件"),
        import_mode: str = Query("insert", description="导入模式：insert-仅插入, update-更新已存在, upsert-插入或更新"),
        created_by: str = Query(..., description="导入者")
):
    """从Excel导入导航数据"""
    try:
        # 验证文件类型
        if not file.filename.endswith(('.xlsx', '.xls')):
            return {
                "code": 400,
                "message": "请上传Excel文件(.xlsx或.xls格式)",
                "data": None
            }

        # 读取Excel文件
        contents = await file.read()
        df = pd.read_excel(io.BytesIO(contents))

        # 验证必需列
        required_columns = ['页面名称', '场景ID', '导航路径']
        missing_columns = [col for col in required_columns if col not in df.columns]
        if missing_columns:
            return {
                "code": 400,
                "message": f"Excel文件缺少必需列: {', '.join(missing_columns)}",
                "data": None
            }

        # 处理数据
        import_data = []
        for index, row in df.iterrows():
            try:
                item_data = {
                    "scene_id": str(row['场景ID']),
                    "page_name": str(row['页面名称']),
                    "navigation_path": str(row['导航路径']),
                    "tenant_id": str(row.get('租户ID', 'default')),
                    "page_tabs": str(row.get('页面标签页', '')).split(',') if pd.notna(row.get('页面标签页')) else [],
                    "function_desc_list": str(row.get('功能描述', '')).split(',') if pd.notna(
                        row.get('功能描述')) else [],
                    "operation_desc_list": str(row.get('操作描述', '')).split(',') if pd.notna(
                        row.get('操作描述')) else [],
                    "prev_path_list": str(row.get('前置路径', '')).split(',') if pd.notna(row.get('前置路径')) else [],
                    "next_path_list": str(row.get('后置路径', '')).split(',') if pd.notna(row.get('后置路径')) else []
                }
                import_data.append(item_data)
            except Exception as row_error:
                return {
                    "code": 400,
                    "message": f"第{index + 2}行数据格式错误: {str(row_error)}",
                    "data": None
                }

        # 调用服务层进行批量导入
        result = await AIWebApiCallingService.batch_import(import_data, import_mode, created_by)
        return {
            "code": 200,
            "message": "导入成功",
            "data": result
        }
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"导入Excel失败: {str(e)}")


@router.post("/search", summary="搜索导航页面")
async def search_navigation(search_request: AIWebApiCallingSearchRequest):
    """搜索导航页面"""
    try:
        # 调用服务层搜索导航页面
        result = await AIWebApiCallingService.search(search_request)
        return {
            "code": 200,
            "message": "搜索导航页面成功",
            "data": result
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"搜索导航页面失败: {str(e)}")


@router.put("/{page_id}/paths", summary="更新页面路径关系")
async def update_navigation_paths(page_id: str, path_data: AIWebApiCallingPathUpdate):
    """更新页面路径关系"""
    try:
        # 调用服务层更新页面路径关系
        success = await AIWebApiCallingService.update_paths(page_id, path_data)
        if success:
            return {
                "code": 200,
                "message": "页面路径关系更新成功",
                "data": {
                    "page_id": page_id,
                    "prev_path_list": path_data.prev_path_list,
                    "next_path_list": path_data.next_path_list
                }
            }
        else:
            return {
                "code": 404,
                "message": "导航页面不存在",
                "data": None
            }
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"更新页面路径关系失败: {str(e)}")


@router.get("/template/download", summary="下载Excel导入模板")
async def download_import_template():
    """下载Excel导入模板"""
    try:
        # 创建模板数据
        template_data = [
            {
                "页面名称": "示例页面",
                "场景ID": "example-scene-id",
                "租户ID": "default",
                "导航路径": "/example/path",
                "页面标签页": "示例标签页1,示例标签页2",
                "功能描述": "功能1,功能2",
                "操作描述": "操作1,操作2",
                "前置路径": "prev-page-id-1,prev-page-id-2",
                "后置路径": "next-page-id-1,next-page-id-2"
            }
        ]

        # 创建DataFrame
        df = pd.DataFrame(template_data)

        # 创建Excel文件
        output = io.BytesIO()
        with pd.ExcelWriter(output, engine='openpyxl') as writer:
            df.to_excel(writer, sheet_name='导航数据模板', index=False)

            # 添加说明工作表
            instructions = pd.DataFrame([
                {"字段名": "页面名称", "是否必填": "是", "说明": "页面的中文名称"},
                {"字段名": "场景ID", "是否必填": "是", "说明": "关联的业务场景ID，需为UUID格式"},
                {"字段名": "租户ID", "是否必填": "否", "说明": "租户标识，默认为default"},
                {"字段名": "导航路径", "是否必填": "是", "说明": "页面URL路径"},
                {"字段名": "页面标签页", "是否必填": "否", "说明": "页面标签页名称，多个用逗号分隔"},
                {"字段名": "功能描述", "是否必填": "否", "说明": "页面功能描述，多个用逗号分隔"},
                {"字段名": "操作描述", "是否必填": "否", "说明": "页面操作描述，多个用逗号分隔"},
                {"字段名": "前置路径", "是否必填": "否", "说明": "前置页面ID，多个用逗号分隔"},
                {"字段名": "后置路径", "是否必填": "否", "说明": "后置页面ID，多个用逗号分隔"}
            ])
            instructions.to_excel(writer, sheet_name='字段说明', index=False)

        output.seek(0)

        # 返回文件流
        headers = {
            'Content-Disposition': 'attachment; filename="navigation_import_template.xlsx"'
        }

        return StreamingResponse(
            io.BytesIO(output.read()),
            media_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
            headers=headers
        )
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"下载模板失败: {str(e)}")


@router.get("/search/similar", summary="混合检索相似导航内容")
async def search_similar_content(
        query: str = Query(..., description="搜索查询内容"),
        scene_id: str = Query(..., description="场景ID"),
        limit: int = Query(10, ge=1, le=50, description="返回结果数量限制"),
        vector_weight: float = Query(0.7, ge=0.0, le=1.0, description="向量检索权重"),
        bm25_weight: float = Query(0.3, ge=0.0, le=1.0, description="BM25检索权重")
):
    """
    混合检索相似导航内容 - 使用向量检索和BM25算法
    
    该接口结合了语义相似度检索(向量检索)和关键词匹配检索(BM25)，
    提供更准确和全面的搜索结果。
    
    参数说明：
    - query: 搜索查询内容
    - scene_id: 场景ID，用于限定搜索范围
    - limit: 返回结果数量限制 (1-50)
    - vector_weight: 向量检索权重 (0.0-1.0)
    - bm25_weight: BM25检索权重 (0.0-1.0)
    
    注意：vector_weight + bm25_weight 应该等于 1.0
    """
    try:
        # 验证权重参数
        if abs(vector_weight + bm25_weight - 1.0) > 0.01:
            return {
                "code": 400,
                "message": "向量权重和BM25权重之和必须等于1.0",
                "data": None
            }
        
        # 调用服务层进行混合检索
        results = await AIWebApiCallingService.search_similar_content(
            query=query,
            scene_id=scene_id,
            limit=limit,
            vector_weight=vector_weight,
            bm25_weight=bm25_weight
        )
        
        return {
            "code": 200,
            "message": f"混合检索完成，共找到 {len(results)} 个相似内容",
            "data": {
                "query": query,
                "scene_id": scene_id,
                "search_params": {
                    "vector_weight": vector_weight,
                    "bm25_weight": bm25_weight,
                    "limit": limit
                },
                "results": results,
                "total_count": len(results)
            }
        }
        
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"混合检索失败: {str(e)}")
